/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */
using System;
using System.Collections;
using Velocity4Net.App.Events;
using Velocity4Net.Runtime.ResourceManage;
using Velocity4Net.Util.Introspection;

namespace Velocity4Net.Ctx
{
    /**
     *  This adapter class is the container for all context types for internal
     *  use.  The AST now uses this class rather than the app-level Context
     *  interface to allow flexibility in the future.
     *
     *  Currently, we have two context interfaces which must be supported :
     *  <ul>
     *  <li> Context : used for application/template data access
     *  <li> InternalHousekeepingContext : used for internal housekeeping and caching
     *  <li> InternalWrapperContext : used for getting root cache context and other
     *       such.
     *  <li> InternalEventContext : for event handling.
     *  </ul>
     *
     *  This class implements the two interfaces to ensure that all methods are
     *  supported.  When adding to the interfaces, or adding more context
     *  functionality, the interface is the primary definition, so alter that first
     *  and then all classes as necessary.  As of this writing, this would be
     *  the only class affected by changes to InternalContext
     *
     *  This class ensures that an InternalContextBase is available for internal
     *  use.  If an application constructs their own Context-implementing
     *  object w/o subclassing AbstractContext, it may be that support for
     *  InternalContext is not available.  Therefore, InternalContextAdapter will
     *  create an InternalContextBase if necessary for this support.  Note that
     *  if this is necessary, internal information such as node-cache data will be
     *  lost from use to use of the context.  This may or may not be important,
     *  depending upon application.
     *
     *
     * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
     * @version $Id: InternalContextAdapterImpl.java 731266 2009-01-04 15:11:20Z byron $
     */
    public sealed class InternalContextAdapterImpl : InternalContextAdapter
    {
        /**
         *  the user data Context that we are wrapping
         */
        IContext context = null;

        /**
         *  the ICB we are wrapping.  We may need to make one
         *  if the user data context implementation doesn't
         *  support one.  The default AbstractContext-derived
         *  VelocityContext does, and it's recommended that
         *  people derive new contexts from AbstractContext
         *  rather than piecing things together
         */
        InternalHousekeepingContext icb = null;

        /**
         *  The InternalEventContext that we are wrapping.  If
         *  the context passed to us doesn't support it, no
         *  biggie.  We don't make it for them - since its a
         *  user context thing, nothing gained by making one
         *  for them now
         */
        InternalEventContext iec = null;

        /**
         *  CTOR takes a Context and wraps it, delegating all 'data' calls
         *  to it.
         *
         *  For support of internal contexts, it will create an InternalContextBase
         *  if need be.
         * @param c
         */
        public InternalContextAdapterImpl(IContext c)
        {
            context = c;

            if (!(c is InternalHousekeepingContext))
            {
                icb = new InternalContextBase();
            }
            else
            {
                icb = (InternalHousekeepingContext)context;
            }

            if (c is InternalEventContext)
            {
                iec = (InternalEventContext)context;
            }
        }

        /* --- InternalHousekeepingContext interface methods --- */

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#pushCurrentTemplateName(java.lang.String)
         */
        public void PushCurrentTemplateName(String s)
        {
            icb.PushCurrentTemplateName(s);
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#popCurrentTemplateName()
         */
        public void PopCurrentTemplateName()
        {
            icb.PopCurrentTemplateName();
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentTemplateName()
         */
        public String CurrentTemplateName
        {
            get
            {
                return icb.CurrentTemplateName;
            }
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#getTemplateNameStack()
         */
        public Object[] TemplateNameStack
        {
            get
            {
                return icb.TemplateNameStack;
            }
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#pushCurrentMacroName(java.lang.String)
         * @since 1.6
         */
        public void PushCurrentMacroName(String s)
        {
            icb.PushCurrentMacroName(s);
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#popCurrentMacroName()
         * @since 1.6
         */
        public void PopCurrentMacroName()
        {
            icb.PopCurrentMacroName();
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentMacroName()
         * @since 1.6
         */
        public String CurrentMacroName
        {
            get
            {
                return icb.CurrentMacroName;
            }
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentMacroCallDepth()
         * @since 1.6
         */
        public int CurrentMacroCallDepth
        {
            get
            {
                return icb.CurrentMacroCallDepth;
            }
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#getMacroNameStack()
         * @since 1.6
         */
        public Object[] MacroNameStack
        {
            get
            {
                return icb.MacroNameStack;
            }
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#icacheGet(java.lang.Object)
         */
        public IntrospectionCacheData ICacheGet(Object key)
        {
            return icb.ICacheGet(key);
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#icachePut(java.lang.Object, org.apache.velocity.util.introspection.IntrospectionCacheData)
         */
        public void ICachePut(Object key, IntrospectionCacheData o)
        {
            icb.ICachePut(key, o);
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentResource()
         */
        public Resource CurrentResource
        {
            get
            {
                return icb.CurrentResource;
            }
            set
            {
                icb.CurrentResource = value;
            }
        }

        /**
         * @see org.apache.velocity.context.InternalHousekeepingContext#getMacroLibraries()
         * @since 1.6
         */
        public IList MacroLibraries
        {
            get
            {
                return icb.MacroLibraries;
            }
            set
            {
                icb.MacroLibraries = value;
            }
        }

        /* ---  Context interface methods --- */

        /**
         * @see org.apache.velocity.context.Context#put(java.lang.String, java.lang.Object)
         */
        public Object Put(String key, Object value)
        {
            return context.Put(key, value);
        }

        /**
         * @see InternalWrapperContext#localPut(String, Object)
         * @since 1.5
         */
        public Object LocalPut(String key, Object value)
        {
            return Put(key, value);
        }

        /**
         * @see org.apache.velocity.context.Context#get(java.lang.String)
         */
        public Object Get(String key)
        {
            return context.Get(key);
        }

        /**
         * @see org.apache.velocity.context.Context#containsKey(java.lang.Object)
         */
        public bool ContainsKey(Object key)
        {
            return context.ContainsKey(key);
        }

        /**
         * @see org.apache.velocity.context.Context#getKeys()
         */
        public ICollection Keys
        {
            get
            {
                return context.Keys;
            }
        }

        /**
         * @see org.apache.velocity.context.Context#remove(java.lang.Object)
         */
        public Object Remove(Object key)
        {
            return context.Remove(key);
        }


        /* ---- InternalWrapperContext --- */

        /**
         *  returns the user data context that
         *  we are wrapping
         * @return The internal user data context.
         */
        public IContext InternalUserContext
        {
            get
            {
                return context;
            }
        }

        /**
         *  Returns the base context that we are
         *  wrapping. Here, its this, but for other thing
         *  like VM related context contortions, it can
         *  be something else
         * @return The base context.
         */
        public InternalContextAdapter BaseContext
        {
            get
            {
                return this;
            }
        }

        /* -----  InternalEventContext ---- */

        /**
         * @see org.apache.velocity.context.InternalEventContext#attachEventCartridge(org.apache.velocity.app.event.EventCartridge)
         */
        public EventCartridge AttachEventCartridge(EventCartridge ec)
        {
            if (iec != null)
            {
                return iec.AttachEventCartridge(ec);
            }

            return null;
        }

        /**
         * @see org.apache.velocity.context.InternalEventContext#getEventCartridge()
         */
        public EventCartridge EventCartridge
        {
            get
            {
                if (iec != null)
                {
                    return iec.EventCartridge;
                }

                return null;
            }
        }
    }



}
